/*******************************************************************************
 * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Marc R. Hoffmann - initial API and implementation
 *
 *******************************************************************************/
package org.jacoco.report.internal.html.page;

import java.io.IOException;

import org.jacoco.core.JaCoCo;
import org.jacoco.core.analysis.ICounter;
import org.jacoco.core.analysis.ICoverageNode;
import org.jacoco.report.html.ToolEcharts;
import org.jacoco.report.internal.ReportOutputFolder;
import org.jacoco.report.internal.html.AppInforDTO;
import org.jacoco.report.internal.html.HTMLElement;
import org.jacoco.report.internal.html.IHTMLReportContext;
import org.jacoco.report.internal.html.ILinkable;
import org.jacoco.report.internal.html.resources.Resources;
import org.jacoco.report.internal.html.resources.Styles;

/**
 * Base class for HTML page generators. It renders the page skeleton with the
 * breadcrumb, the title and the footer. Every report page is part of a
 * hierarchy and has a parent page (except the root page).
 */
public abstract class ReportPage implements ILinkable {

	private final ReportPage parent;

	/** output folder for this node */
	protected final ReportOutputFolder folder;

	/** context for this report */
	protected final IHTMLReportContext context;

	/** AppInforDTO dto for this report */
	protected AppInforDTO dto;

	/**
	 * Creates a new report page.
	 *
	 * @param parent
	 *            optional hierarchical parent
	 * @param folder
	 *            base folder to create this report in
	 * @param context
	 *            settings context
	 */
	protected ReportPage(final ReportPage parent,
			final ReportOutputFolder folder, final IHTMLReportContext context) {
		this.parent = parent;
		this.context = context;
		this.folder = folder;
	}

	/**
	 * Checks whether this is the root page of the report.
	 *
	 * @return <code>true</code> if this is the root page
	 */
	protected final boolean isRootPage() {
		return parent == null;
	}

	/**
	 * Renders this page's content and optionally additional pages. This method
	 * must be called at most once.
	 *
	 * @param dto
	 *            source dto for this bundle
	 * @throws IOException
	 *             if the page can't be written
	 */
	public void render(AppInforDTO dto) throws IOException {
		final HTMLElement html = new HTMLElement(
				folder.createFile(getFileName()), context.getOutputEncoding());
		html.attr("lang", context.getLocale().getLanguage());
		head(html.head());

		// html.script("https://code.hcharts.cn/11.1.0/highcharts.js");
		// html.script("https://code.hcharts.cn/11.1.0/modules/exporting.js");
		html.script("https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js");
		body(html.body(), false, dto);
		html.close();
	}

	/**
	 * Creates the elements within the head element.
	 *
	 * @param head
	 *            head tag of the page
	 * @throws IOException
	 *             in case of IO problems with the report writer
	 */
	protected void head(final HTMLElement head) throws IOException {
		head.meta("Content-Type", "text/html;charset=UTF-8");
		head.link("stylesheet",
				context.getResources().getLink(folder, Resources.STYLESHEET),
				"text/css");
		head.link("shortcut icon",
				context.getResources().getLink(folder, "report.gif"),
				"image/gif");
		head.title().text(getLinkLabel());
	}

	private void body(final HTMLElement body, boolean isSourcePage,
			AppInforDTO dto) throws IOException {
		/*
		 * body.attr("onload", getOnload()); final HTMLElement navigation =
		 * body.div(Styles.BREADCRUMB); navigation.attr("id", "breadcrumb");
		 * infoLinks(navigation.span(Styles.INFO)); breadcrumb(navigation,
		 * folder); body.h1().text(getLinkLabel()); content(body); footer(body);
		 */
		body.attr("onload", getOnload());
		// 添加汇总数据图表
		if (!isSourcePage) {
			// 创建汇总区域
			final HTMLElement graphDiv = body.div("graph");
			graphDiv.attr("style",
					"border:0px solid lightgray;height:150px;width:750px;margin-top:10px;margin-botom:50px;");
			// 获取汇总数据
			Object summaryData = getSummaryNode(body);
			ICoverageNode summary = null;
			if (summaryData instanceof ICoverageNode) {
				summary = (ICoverageNode) summaryData;
			}

			// 创建汇总区域中标题、统计对象、数据等
			if (summary != null) {
				// createTitleArea(graphDiv, summary);
			}

			// 创建汇总区域图表
			if (summary != null) {
				summary(graphDiv, summary);
				graphDiv.close();
			}
		}

		final HTMLElement navigation = body.div(Styles.BREADCRUMB);
		navigation.attr("id", "breadcrumb");
		infoLinks(navigation.span(Styles.INFO));
		breadcrumb(navigation, folder);
		body.h1().text(getLinkLabel());
		content(body);
		footer(body);
	}

	/**
	 * Returns the onload handler for this page.
	 *
	 * @return handler or <code>null</code>
	 */
	protected String getOnload() {
		return null;
	}

	/**
	 * Inserts additional links on the top right corner.
	 *
	 * @param span
	 *            parent element
	 * @throws IOException
	 *             in case of IO problems with the report writer
	 */
	protected void infoLinks(final HTMLElement span) throws IOException {
		span.a(context.getSessionsPage(), folder);
	}

	private void breadcrumb(final HTMLElement div,
			final ReportOutputFolder base) throws IOException {
		breadcrumbParent(parent, div, base);
		div.span(getLinkStyle()).text(getLinkLabel());
	}

	private static void breadcrumbParent(final ReportPage page,
			final HTMLElement div, final ReportOutputFolder base)
			throws IOException {
		if (page != null) {
			breadcrumbParent(page.parent, div, base);
			div.a(page, base);
			div.text(" > ");
		}
	}

	private void footer(final HTMLElement body) throws IOException {
		final HTMLElement footer = body.div(Styles.FOOTER);
		final HTMLElement versioninfo = footer.span(Styles.RIGHT);
		versioninfo.text("Created with ");
		versioninfo.a(JaCoCo.HOMEURL).text("JaCoCo");
		versioninfo.text(" ");
		versioninfo.text(JaCoCo.VERSION);
		footer.text(context.getFooterText());
	}

	/**
	 * Specifies the local file name of this page.
	 *
	 * @return local file name
	 */
	protected abstract String getFileName();

	/**
	 * Creates the actual content of the page.
	 *
	 * @param body
	 *            body tag of the page
	 * @throws IOException
	 *             in case of IO problems with the report writer
	 */
	protected abstract void content(final HTMLElement body) throws IOException;

	// === ILinkable ===

	public final String getLink(final ReportOutputFolder base) {
		return folder.getLink(base, getFileName());
	}

	public AppInforDTO getDto() {
		return dto;
	}

	protected void createTitleArea(HTMLElement graphDiv,
			ICoverageNode sumnary) {
		try {
			final HTMLElement blank = graphDiv.span("blank");
			blank.attr("style", "height:20px");
			blank.text("");
			blank.element("br");
			// final HTMLElement project = graphDiv.span("project");
			// project.attr("style",
			// "font-size: larger;color: dimgray;margin-left:30px;");
			// project.text("代码覆盖率报告");
			// final HTMLElement location = graphDiv.span("location");
			// location.attr("style",
			// "font-size: xx-small;color:
			// gray;float:right;margin-right:10px;");
			// location.text("统计对象:");
			// graphDiv.element("br");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void summary(HTMLElement graphBody, ICoverageNode summary) {
		try {
			// <div class="outerDIV">
			// <div>
			// 行覆盖统计: 90/1276</br>
			// 方法覆盖统计: 24/478
			// </div>
			// <div>
			// 分支覆盖统计: 9/1104</br>
			// 类覆盖统计: 9/42
			// </div>
			// </div>
			ICounter lineCounter = summary.getLineCounter();
			ICounter branchCounter = summary.getBranchCounter();
			ICounter methodCounter = summary.getMethodCounter();
			ICounter classCounter = summary.getClassCounter();

			String strFormt = "%d/%d";
			HTMLElement table = graphBody.table("");
			{
				final HTMLElement tr = table.thead().tr();
				final HTMLElement td = tr.td();
				HTMLElement div1 = td.div("summaryTitle");
				div1.html("行覆盖统计: "
								+ String.format(strFormt,
										lineCounter.getCoveredCount(),
										lineCounter.getTotalCount()));
				HTMLElement div2 = td.div("summaryTitle");
				div2.html("分支覆盖统计: "
						+ String.format(strFormt,
								branchCounter.getCoveredCount(),
								branchCounter.getTotalCount()));
				HTMLElement div3 = td.div("summaryTitle");
				div3.html("方法覆盖统计: "
						+ String.format(strFormt,
								methodCounter.getCoveredCount(),
								methodCounter.getTotalCount()));
				HTMLElement div4 = td.div("summaryTitle");
				div4.html("类覆盖统计: "
						+ String.format(strFormt,
								classCounter.getCoveredCount(),
								classCounter.getTotalCount()));
			}
			final HTMLElement tbody = table.tbody();
			final HTMLElement tr = tbody.tr();
			final HTMLElement containers = tr.td();

			// HTMLElement div1sum = summaryNum.div("div");
			// // div1sum.html("行覆盖统计: 90/1276</br>方法覆盖统计: 24/478");
			// div1sum.html("行覆盖统计: "
			// + String.format(strFormt, lineCounter.getCoveredCount(),
			// lineCounter.getTotalCount())
			// + "</br>分支覆盖统计: "
			// + String.format(strFormt, branchCounter.getCoveredCount(),
			// branchCounter.getTotalCount()));
			// HTMLElement div2sum = summaryNum.div("div");
			// // div2sum.html("分支覆盖统计: 9/1104</br>类覆盖统计: 9/42");
			// div2sum.html("方法覆盖统计: "
			// + String.format(strFormt, methodCounter.getCoveredCount(),
			// methodCounter.getTotalCount())
			// + "</br>类覆盖统计: "
			// + String.format(strFormt, classCounter.getCoveredCount(),
			// classCounter.getTotalCount()));

			// HTMLElement containers = graphBody.div("container");
			// containers.attr("style", "margin-left:70px;");
			// 生成行覆盖率图表
			HTMLElement divl = containers.div("container1");
			divl.attr("style", "height: 100px;width:160px;float:left");
			ToolEcharts.drawGraph(divl, graphBody, "1", "行 ",
					lineCounter.getCoveredCount(), lineCounter.getMissedCount(),
					lineCounter.getCoveredRatio());
			// 生成分支覆盖率图表
			HTMLElement div2 = containers.div("container2");
			div2.attr("style", "height: 100px;width:160px;float:left");
			ToolEcharts.drawGraph(div2, graphBody, "2", "分支 ",
					branchCounter.getCoveredCount(),
					branchCounter.getMissedCount(),
					branchCounter.getCoveredRatio());
			// 生成方法覆盖率图表
			HTMLElement div3 = containers.div("container3");
			div3.attr("style", "height: 100px;width:160px;float:left");
			ToolEcharts.drawGraph(div3, graphBody, "3", "方法 ",
					methodCounter.getCoveredCount(),
					methodCounter.getMissedCount(),
					methodCounter.getCoveredRatio());
			// 生成类覆盖率图表
			HTMLElement div4 = containers.div("container4");
			div4.attr("style", "height: 100px;width:160px;float:left");
			ToolEcharts.drawGraph(div4, graphBody, "4", "类 ",
					classCounter.getCoveredCount(),
					classCounter.getMissedCount(),
					classCounter.getCoveredRatio());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//
	// @Override
	// public Object getSummaryNode(HTMLElement body) throws IOException {
	// return super.getNode();
	// }
}
